------------------------------------------------------------------------------------
-- NOP-00000, ADD-00001, ADDU-00010, SUB-00011, SUBU-00100, unused from 00101 to 01000
-- AND-01001, OR-01010, XOR-01011, NOR-01100, SLT-01101, 
-- SLL-01110, SRL-01111, SRA-10000, BEQ-10001, BNE-10010, SLA-10011
-- MULTU-10100, MULT-10101
-- DIVU -10110, DIV -10111

--add 00
--sub 01
------------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity internalALU is
    Port ( input1 : in  STD_LOGIC_VECTOR (31 downto 0);
           input2 : in  STD_LOGIC_VECTOR (31 downto 0);
           output : out  STD_LOGIC_VECTOR (31 downto 0);
           opcode : in  STD_LOGIC_VECTOR (4 downto 0);
           cout : out  STD_LOGIC);
end internalALU;

architecture Behavioral of internalALU is
	
	constant OP_ADD	: STD_LOGIC_VECTOR :="00001";
	constant OP_ADDU	: STD_LOGIC_VECTOR :="00010";
	constant OP_SUB	: STD_LOGIC_VECTOR :="00011";
	constant OP_SUBU	: STD_LOGIC_VECTOR :="00100";
	constant OP_AND	: STD_LOGIC_VECTOR :="01001";
	constant OP_OR		: STD_LOGIC_VECTOR :="01010";
	constant OP_XOR 	: STD_LOGIC_VECTOR :="01011";
	constant OP_NOR 	: STD_LOGIC_VECTOR :="01100";
	constant OP_SLL 	: STD_LOGIC_VECTOR :="01110";
	constant OP_SRL 	: STD_LOGIC_VECTOR :="01111";
	constant OP_SRA 	: STD_LOGIC_VECTOR :="10000";
	constant OP_SLA 	: STD_LOGIC_VECTOR :="10011";
	constant OP_BEQ	: STD_LOGIC_VECTOR :="10001";
	constant OP_BNE 	: STD_LOGIC_VECTOR :="10010";
	constant OP_SLT 	: STD_LOGIC_VECTOR :="01101";

	component LOGIC_Unit is 
	port(
		OP :  in 	std_logic_vector(1 downto 0);
		A 	: 	in 	std_logic_vector(31 downto 0);
		B 	: 	in 	std_logic_vector(31 downto 0);
		S 	: 	out 	std_logic_vector(31 downto 0)
	);
	end component;

	component full_cla_adder is
    Port ( a : in  STD_LOGIC_VECTOR (31 downto 0);
           b : in  STD_LOGIC_VECTOR (31 downto 0);
           cin : in  STD_LOGIC;
           sub : in  STD_LOGIC_VECTOR (1 downto 0);
           sum : out  STD_LOGIC_VECTOR (31 downto 0);
           cout : out  STD_LOGIC);
	end component;
	
	component shifter_32bits is
    Port ( input : in  STD_LOGIC_VECTOR (31 downto 0);
           shift_value : in  STD_LOGIC_VECTOR (4 downto 0);
			  operation : in STD_LOGIC_VECTOR (1 downto 0);
           output : out  STD_LOGIC_VECTOR (31 downto 0));
	end component;
	
	signal decode_sig : STD_LOGIC_VECTOR(9 downto 0);
	signal logic_output : STD_LOGIC_VECTOR(31 downto 0);
	signal adder_output : STD_LOGIC_VECTOR(31 downto 0);
	signal shift_output : STD_LOGIC_VECTOR(31 downto 0);
	signal comparison_output : STD_LOGIC_VECTOR(31 downto 0);
	--signal adder_cout : STD_LOGIC;
	--signal adder_cin : STD_LOGIC;
	signal bne_result : STD_LOGIC;
	signal beq_result : STD_LOGIC;

begin

	logic : LOGIC_Unit port map(decode_sig(7 downto 6), input1, input2, logic_output);
	adder : full_cla_adder port map(input1, input2, decode_sig(4), decode_sig(5 downto 4), adder_output, cout);
	shifter : shifter_32bits port map(input1, input2(4 downto 0), decode_sig(3 downto 2), shift_output);
	
	process(input1, input2, opcode)
	begin
		case opcode is
			when OP_BEQ => decode_sig <= "0000010011"; --00xx01xx11
			when OP_BNE => decode_sig <= "0100010011"; --01xx01xx11
			when OP_SLT => decode_sig <= "1000010011"; --10xx01xx11
			when OP_AND => decode_sig <= "0000000000"; --xx00xxxx00
			when OP_OR  => decode_sig <= "0001000000"; --xx01xxxx00
			when OP_XOR => decode_sig <= "0010000000"; --xx10xxxx00
			when OP_NOR => decode_sig <= "0011000000"; --xx11xxxx00
			when OP_ADD	=> decode_sig <= "0000000001"; --xxxx00xx01
			when OP_ADDU=> decode_sig <= "0000000001"; --xxxx00xx01
			when OP_SUB => decode_sig <= "0000010001"; --xxxx01xx01
			when OP_SUBU=> decode_sig <= "0000010001"; --xxxx01xx01
			when OP_SLL => decode_sig <= "0000000010"; --xxxxxx0010
			when OP_SLA => decode_sig <= "0000000110"; --xxxxxx0110
			when OP_SRL => decode_sig <= "0000001010"; --xxxxxx1010
			when OP_SRA => decode_sig <= "0000001110"; --xxxxxx1110
			when others => decode_sig <= (others =>'1');
		end case;
	end process;
	
	process(adder_output)
		variable temp : std_logic;
	begin
		temp := adder_output(0) or adder_output(1);
		for i in 2 to 31 loop
			temp := adder_output(i) or temp;
		end loop;
		bne_result <= temp;
		beq_result <= not temp;
	end process;
	
	process(decode_sig(9 downto 8),beq_result,bne_result,adder_output(31))
	begin
		case decode_sig(9 downto 8) is
			when "00" => comparison_output <= (0=> beq_result, others=>'0');
			when "01" => comparison_output <= (0=> bne_result, others=>'0');
			when "10" => comparison_output <= (0=> adder_output(31), others=>'0');
			when others => comparison_output <= (others =>'0');
		end case;
	end process;
	
	process(logic_output, adder_output, shift_output, comparison_output, decode_sig(1 downto 0))
	begin
		case decode_sig(1 downto 0) is
			when "00" => output <= logic_output;
			when "01" => output <= adder_output;
			when "10" => output <= shift_output;
			when "11" => output <= comparison_output;
			when others => output <= (others => '0');
		end case;
	end process;

end Behavioral;

